//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<observer.h>
///	@path	~/src/lib/utilities/
///	@date	2007/11/10
///	@desc	Data observer.

#pragma once

#include "xeres.h"

#include "lib/utilities/string.h"
#include "lib/utilities/time.h"
#include "lib/utilities/dir_tree.h"
#include "lib/utilities/callback.h"
#include "lib/utilities/helper.h"

#include <vector>
#include "boost/shared_ptr.hpp"
#include "boost/any.hpp"

namespace xeres {

	/*! 
		\brief	Counter statistic support by counter-observer.
	*/
#if (XERES_CONFIG_ENABLE_COUNTER_STAT)

#	define	COUNTER_SCOPE( NAME )	do{\
									static CounterHolder s_privateScopeCounter( NAME );\
									s_privateScopeCounter.Start();\

#	define	COUNTER_END()			s_privateScopeCounter.End(); }while(0)

#	define	COUNTER_GUARD( NAME )	static CounterHolder s_counterHolder( NAME ); Guard<_counter> s_counterGuard( s_counterHolder )

#	define	OBSERVE_SWITCH			ObserveModify
#	define	OBSERVE_WATCH			ObserveOnly
#	define	OBSERVE_STAT

#else

#	define	COUNTER_SCOPE( NAME )
#	define	COUNTER_END()
#	define	COUNTER_GUARD( NAME )
#	define	OBSERVE_SWITCH			__noop
#	define	OBSERVE_WATCH			__noop
#	define	OBSERVE_STAT			__noop

#endif // XERES_CONFIG_ENABLE_COUNTER_STAT

	/// \brief Observer type
	enum ObserverType
	{
		OBSERVER_READONLY = 0 ,
		OBSERVER_WRITABLE = 1 ,
		OBSERVER_DIR = 2,
		OBSERVER_last , // Also used in visiting dir to indicate directory access end.
	};

	// forward declaration
	class Observer;

	// observation function.
	typedef function<bool(ObserverType,Observer*,const WString&)> Observation;

	/*
		\class	Observer
		\brief	An interface to observer, reading/writing debug values.
	*/
	class Observer
	{
	public:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		Observer( ObserverType accessType );

		/// \dtor
		virtual ~Observer( void );

		//@}

		/// \brief	Get root observer.
		static Observer * root( void );

	public:

		/// \brief	Visit all observer children.
		virtual bool VisitChildren( const WString& path , Observation observation );

		/// \brief
		virtual bool AddChild( const WString& name , Observer * child );

		/// \brief
		virtual boost::any GetValue( void ) = 0;

		/// \brief
		virtual bool SetValue( const boost::any& value ) = 0;

		/// \brief
		virtual Observer * GetChild( const WString& name );

		/// \brief
		virtual bool HasChild( void ) const { return false; }

		/// \brief
		virtual Observer * GetChildByPath( const WString& path );

		/// \brief	Get access type.
		virtual ObserverType GetAccessType( void ) const { 
			return m_accessType;
		}

		/// \brief	Get description.
		const WString& GetDesc( void ) const {
			return m_desc;
		}
		
		/// \brief	Set description.
		void SetDesc( const WString& desc ) {
			m_desc = desc;
		}

		/// \brief Add to observer chain.
		void AddToChain( const WString& path , Observer * node );

	private:

		//@ data
		ObserverType		m_accessType;
		WString				m_desc;
	};

	/*! 
		\class	DirectoryObserver
		\brief
	*/
	class DirectoryObserver : public Observer
	{
	public:

		/// \name Constructor & Destructor
		//@{

		/// \ctor
		DirectoryObserver( void );

		/// \dtor
		virtual ~DirectoryObserver( void );

		//@}

		/// \brief	Visit all observer children.
		virtual bool VisitChildren( const WString& path , Observation observation );

		/// \brief
		virtual bool AddChild( const WString& name , Observer * child );

		/// \brief
		virtual boost::any GetValue( void );

		/// \brief
		virtual bool SetValue( const boost::any& value );

		/// \brief
		virtual Observer * GetChild( const WString& name );

		/// \brief
		virtual bool HasChild( void ) const { return true; }

		/// \brief
		virtual Observer * GetChildByPath( const WString& path );

		/// \brief
		bool HasChildren( void ) const { return !m_directory.empty(); }

	private:

		//@ data
		struct _DirData
		{
			boost::shared_ptr<Observer> observer;
			WString label;
		};

		std::vector< _DirData >		m_directory;
	};

	/*! 
		\class	ValueObserver
		\brief	
	*/
	template<
		typename _Type
	> class ValueObserver : public Observer
	{
	public:

		/// \ctor
		ValueObserver( _Type& veryValueRef , ObserverType access )
			: Observer( access )
			, m_valueRef( veryValueRef )
		{
		}

		/// \brief
		virtual boost::any GetValue( void )
		{
			return boost::any( m_valueRef );
		}

		/// \brief
		virtual bool SetValue( const boost::any& value )
		{
			if( GetAccessType() != OBSERVER_WRITABLE )
				return false;

			try
			{
				m_valueRef = boost::any_cast<_Type>( value );
			}
			catch( boost::bad_any_cast )
			{
				return false;
			}
			return true;
		}

	private:

		//@ data
		_Type&		m_valueRef;
	};

	/// \brief	Add Observer
	void AddObserver( const WString& desc , Observer * observer );

	/// \brief	Observes a value.
	template<
		typename _Type
	> void ObserveModify( const WString& desc , _Type& value )
	{
		Observer * observer = new ValueObserver<_Type>( value , OBSERVER_WRITABLE );
		AddObserver( desc , observer );
	}

	template<
		typename _Type
	> void ObserveOnly( const WString& desc , _Type& value )
	{
		Observer * observer = new ValueObserver<_Type>( value , OBSERVER_READONLY );
		AddObserver( desc , observer );
	}

	/*! 
		\class	ProcedureObserver
		\brief
	*/
	template<
		typename _Type
	>  class ProcedureObserver : public Observer
	{
	public:

		/// \ctor
		ProcedureObserver( function<_Type(void)> func )
			: Observer( OBSERVER_READONLY )
			, m_func( func )
		{
		}

		/// \brief
		virtual boost::any GetValue( void )
		{
			return boost::any( m_func() );
		}

		/// \brief
		virtual bool SetValue( const boost::any& value )
		{
			FATAL_ABORT( _S("Unexpected SetValue") );
			return false;
		}

	private:

		//@ data
		function<_Type(void)>	m_func;
	};

	/*! 
		\class	PropertyObserver
		\brief
	*/
	template<
		typename _Type
	> class PropertyObserver : public Observer
	{
	public:

		/// \ctor
		PropertyObserver( function<_Type(void)> get , function<void(_Type)> set )
			: Observer( OBSERVER_WRITABLE )
			, m_get( get )
			, m_set( set )
		{
		}

		/// \brief
		virtual boost::any GetValue( void )
		{
			return boost::any( m_get() );
		}

		/// \brief
		virtual bool SetValue( const boost::any& value )
		{
			_Type tmp;
			try
			{
				tmp = any_cast<_Type>( value );
			}
			catch( boost::bad_any_cast )
			{
				return false;
			}
			m_set( tmp );
			return true;
		}

	private:

		//@ data
		function<_Type(void)>	m_get;
		function<void(_Type)>	m_set;
	};
	
	/*! 
		\class	CounterObserver
		\brief
	*/
	class CounterObserver : public DirectoryObserver
	{
	public:

		/// \ctor
		CounterObserver( void );

		/// \dtor
		virtual ~CounterObserver( void );

		/// \brief
		virtual boost::any GetValue( void );

		/// \brief	Get access type.
		virtual ObserverType GetAccessType( void ) const;

		/// \brief	Increase frame counter.
		static void NextFrame( void );
		
	private:

		friend class CounterHolder;

		// @data
		Counter				m_counter;
		Counter				m_last;

		// all counters
		static std::deque< CounterObserver * >	s_counters;

	};

	/*! 
		\class	CounterHolder
		\brief	
	*/
	class CounterHolder
	{
	public:

		/// \ctor
		CounterHolder( const WString& path );

		/// \dtor
		~CounterHolder( void );

		/// \brief	Start counter.
		void Start( void );

		/// \brief	End counter.
		void End( void );

	private:

		// local counter
		Counter					m_counter;

		// parent counter
		CounterHolder *			m_parent;

		// modify counter observer.
		CounterObserver *		m_observer;

		/// \ctor
		CounterHolder( void );

		// current counter
		static CounterHolder * Current( CounterHolder * next_current );
		static CounterHolder& CounterRoot( void );
	};

	struct _counter;

	/*! 
		\brief	Specialization of counter.
	*/
	template<> struct Guard<_counter>
	{
		/// \ctor
		Guard( CounterHolder& holder )
			: m_holder( holder )
		{
			m_holder.Start();
		}

		/// \dtor
		~Guard( void )
		{
			m_holder.End();
		}

	private:

		CounterHolder m_holder;
	};

} // namespace xeres
